package com.leizi.igym.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leizi.igym.constant.CommonConstant;
import com.leizi.igym.constant.MemberConstant;
import com.leizi.igym.domain.Member;
import com.leizi.igym.dto.DoughnutStatisticsDTO;
import com.leizi.igym.dto.LineStatisticsDTO;
import com.leizi.igym.dto.MemberAddDTO;
import com.leizi.igym.dto.MemberPageQueryDTO;
import com.leizi.igym.enums.CardEnum;
import com.leizi.igym.enums.DoughnutStatisticsTypeEnum;
import com.leizi.igym.enums.LineStatisticsDateEnum;
import com.leizi.igym.enums.ReturnCodeEnum;
import com.leizi.igym.exception.BusinessException;
import com.leizi.igym.service.MemberService;
import com.leizi.igym.mapper.MemberMapper;
import com.leizi.igym.utils.DateQWUtils;
import com.leizi.igym.utils.ThrowUtils;
import com.leizi.igym.vo.MemberVO;
import io.jsonwebtoken.impl.crypto.MacProvider;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author PC
 * @description 针对表【t_member】的数据库操作Service实现
 * @createDate 2024-04-29 09:45:06
 */
@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member>
        implements MemberService {

    @Override
    public QueryWrapper<Member> getQueryWrapper(MemberPageQueryDTO dto) {

        ThrowUtils.throwIf(Objects.isNull(dto), ReturnCodeEnum.PARAMS_ERROR);

        //  获取分页查询参数
        String memberName = dto.getMemberName();
        String phone = dto.getPhone();
        Long id = dto.getId();
        String level = dto.getLevel();
        LocalDate beginTime = dto.getBeginTime();
        LocalDate endTime = dto.getEndTime();


        //  根据参数构造queryWrapper
        QueryWrapper<Member> qw = new QueryWrapper<>();

        qw.like(Objects.nonNull(id), "id", id);
        qw.like(!StringUtils.isBlank(memberName), "member_Name", memberName);
        qw.eq(!StringUtils.isBlank(level), "level", level);
        qw.like(!StringUtils.isBlank(phone), "phone", phone);
        DateQWUtils.getDateQWForEmp(qw, beginTime, endTime);
        qw.orderByDesc("create_time");

        return qw;

    }

    @Override
    public List<MemberVO> getMemberVOPage(Page<Member> page) {
        ThrowUtils.throwIf(ObjectUtils.isEmpty(page), ReturnCodeEnum.PARAMS_ERROR);
        List<Member> memberList = page.getRecords();
        return memberList.stream().map(member -> {
            MemberVO memberVO = new MemberVO();
            BeanUtils.copyProperties(member, memberVO);
            return memberVO;
        }).collect(Collectors.toList());
    }

    @Override
    public MemberVO getMemberById(Long id) {
        ThrowUtils.throwIf(Objects.isNull(id) || id < 0, ReturnCodeEnum.PARAMS_ERROR);
        Member dbMember = this.getBaseMapper().selectById(id);
        ThrowUtils.throwIf(Objects.isNull(dbMember), ReturnCodeEnum.SYSTEM_ERROR);
        MemberVO memberVO = new MemberVO();
        BeanUtils.copyProperties(dbMember, memberVO);
        return memberVO;
    }

    @Override
    public boolean removeMemberBatch(List<Long> ids) {
        // 校验id
        if (ids == null || ids.size() == 0) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "id列表为空，无法删除");
        }
        // 判断用户是否存在
        for (Long id : ids) {
            if (getById(id) == null) {
                throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "存在非法会员，无法删除");
            }
        }

        if (!removeBatchByIds(ids)) {
            throw new BusinessException(ReturnCodeEnum.SYSTEM_ERROR);
        }

        return true;
    }

    @Override
    public boolean updateMemberInAdmin(Member member) {
        ThrowUtils.throwIf(Objects.isNull(member), ReturnCodeEnum.PARAMS_ERROR);
        String memberName = member.getMemberName();
        String avatar = member.getAvatar();
        Integer gender = member.getGender();
        String phone = member.getPhone();
        String level = member.getLevel();

        // todo 参数合法性校验
        // 参数非空校验
        if (StringUtils.isAnyBlank(memberName, avatar, phone, level)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        if (!CommonConstant.GENDER_LIST.contains(gender)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        if (!MemberConstant.LEVEL_LIST.contains(level)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        // 插入消息
        member.setExpireTime(member.getCreateTime().toLocalDate().plusDays(CardEnum.getDateNum(level) - 1));
        Integer result = this.getBaseMapper().updateById(member);
        return null != result && result >= 1;
    }

    @Override
    public boolean saveMember(MemberAddDTO dto) {
        ThrowUtils.throwIf(Objects.isNull(dto), ReturnCodeEnum.PARAMS_ERROR);
        String level = dto.getLevel();
        String memberName = dto.getMemberName();
        String phone = dto.getPhone();
        Integer age = dto.getAge();
        String avatar = dto.getAvatar();
        Integer gender = dto.getGender();
        if (StringUtils.isAnyBlank(memberName, phone, avatar)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }
        if (!MemberConstant.LEVEL_LIST.contains(level)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "会员等级有误！");
        }
        if (age < 0) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }
        if (!CommonConstant.GENDER_LIST.contains(gender)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "会员等级有误！");
        }

        Member member = new Member();
        BeanUtils.copyProperties(dto, member);
        Integer dateNum = CardEnum.getDateNum(level);
        member.setExpireTime(LocalDate.now().plusDays(dateNum - 1));
        member.setCdk(DigestUtil.sha256Hex(memberName + age + level));
        int insert = this.getBaseMapper().insert(member);
        if (insert < 1) {
            throw new BusinessException(ReturnCodeEnum.SAVE_ERROR, "新增会员失败！");
        }
        return true;
    }

    @Override
    public List<DoughnutStatisticsDTO> getDoughnutStatisticsByType(String type) {
        if (StringUtils.isBlank(type) || Objects.isNull(DoughnutStatisticsTypeEnum.getTypeValue(type))) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }
        if (type.equals(DoughnutStatisticsTypeEnum.GENDER.getType())) {
            return this.getBaseMapper()
                    .selectDoughnutStatisticsByGender();
        }

        if (type.equals(DoughnutStatisticsTypeEnum.LEVEL.getType())) {
            return this.getBaseMapper().selectDoughnutStatisticsByLevel();
        }

        if (type.equals(DoughnutStatisticsTypeEnum.AGE.getType())) {
            return this.getBaseMapper().selectDoughnutStatisticsByAge();
        }

        return Collections.emptyList();
    }

    @Override
    public LineStatisticsDTO getLineStatisticsByDate(Integer date) {
        if (Objects.isNull(date) || Objects.isNull(LineStatisticsDateEnum.getDateValue(date))) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }
        Map map = new HashMap<>();
        List<String> dateList = new ArrayList<>();
        List<Integer> newCountList = new ArrayList<>();
        List<Integer> allCountList = new ArrayList<>();
        LocalDate now = LocalDate.now();

        for (int i = date - 1; i >= 0; i--) {
            LocalDate today = now.minusDays(i);
            dateList.add(today.toString());
            LocalDateTime endTime = LocalDateTime.of(today, LocalTime.MAX);
            map.put("endTime", endTime);
            allCountList.add(this.getBaseMapper().selectAllCount(map));
            LocalDateTime beginTime = LocalDateTime.of(today, LocalTime.MIN);
            map.put("beginTime", beginTime);
            newCountList.add(this.getBaseMapper().selectNewCount(map));
        }
        return LineStatisticsDTO
                .builder()
                .dateList(dateList)
                .newCountList(newCountList)
                .allCountList(allCountList)
                .build();
    }
}




